package com.yanqu.xiuxian.crosssystem.manger.elementalbonds.logic;

import com.yanqu.xiuxian.config.elementalbonds.enums.ElementalBondsShapeType;
import com.yanqu.xiuxian.crosssystem.manger.elementalbonds.config.ElementalBondsShapeConfig;
import com.yanqu.xiuxian.crosssystem.manger.elementalbonds.entity.ElementalBondsBlock;
import com.yanqu.xiuxian.crosssystem.manger.elementalbonds.result.ElementalBondsShapeMatchResult;

import java.util.*;

public class ElementalBondsShapeLogic {

    /**
     * 所有形状，按匹配顺序来
     */
    public static List<ElementalBondsShapeConfig> elementalBondsShapeConfigList = new ArrayList<>();

    static {
        initElementalBondsShapeConfigList();
    }

    /**
     * 初始化形状
     */
    public static void initElementalBondsShapeConfigList() {
        List<ElementalBondsShapeConfig> list = new ArrayList<>();

        for (ElementalBondsShapeType elementalBondsShapeType : ElementalBondsShapeType.values()) {
            int[][] value = elementalBondsShapeType.getValue();

            // 所需格子数量
            int needCount = 0;
            for (int[] val : value) {
                for (int v : val) {
                    if (v == 1) {
                        needCount++;
                    }
                }
            }

            // 【不重复的map】
            Map<String, List<List<Integer>>> noRepeatedMap = new HashMap<>();

            // 先来一份
            List<List<Integer>> listList = buildMatchPoint(value);
            if (listList != null) {
                noRepeatedMap.putIfAbsent(getPointListKey(listList), listList);
            }
            // 旋转再来三份
            for (int i = 0; i < 3; i++) {
                value = rotate90(value);
                listList = buildMatchPoint(value);
                if (listList != null) {
                    noRepeatedMap.putIfAbsent(getPointListKey(listList), listList);
                }
            }
            // 翻转再来一份
            value = rotate90(value);
            value = flipHorizontally(value);
            listList = buildMatchPoint(value);
            if (listList != null) {
                noRepeatedMap.putIfAbsent(getPointListKey(listList), listList);
            }
            // 旋转再来三份
            for (int i = 0; i < 3; i++) {
                value = rotate90(value);
                listList = buildMatchPoint(value);
                if (listList != null) {
                    noRepeatedMap.putIfAbsent(getPointListKey(listList), listList);
                }
            }

            for (List<List<Integer>> lists : noRepeatedMap.values()) {
                list.add(new ElementalBondsShapeConfig(needCount, lists, elementalBondsShapeType));
            }
        }

        elementalBondsShapeConfigList = list;
    }

    /**
     * 匹配形状
     */
    public static ElementalBondsShapeMatchResult matchShape(List<ElementalBondsBlock> elementalBondsBlockList) {
        // 遍历所有形状一个个匹配
        for (ElementalBondsShapeConfig elementalBondsShapeConfig : elementalBondsShapeConfigList) {
            // 跳过数量不够的形状
            if (elementalBondsBlockList.size() < elementalBondsShapeConfig.getNeedCount()) {
                continue;
            }
            // 各个点为基点都试一下
            List<List<Integer>> matchPointList = elementalBondsShapeConfig.getMatchPoint();
            for (ElementalBondsBlock elementalBondsBlock : elementalBondsBlockList) {

                // 匹配结果
                List<ElementalBondsBlock> matchElementalBondsBlockList = new ArrayList<>(); // 形状匹配list是从小到大的，这里添加结果也是从小到大的
                matchElementalBondsBlockList.add(elementalBondsBlock);
                boolean matchSuccess = true;

                for (List<Integer> matchPoint : matchPointList) {
                    int matchX = elementalBondsBlock.getX() + matchPoint.get(0);
                    int matchY = elementalBondsBlock.getY() + matchPoint.get(1);
                    Optional<ElementalBondsBlock> elementalBondsBlockOptional = elementalBondsBlockList.stream()
                            .filter(block -> block.getX() == matchX && block.getY() == matchY)
                            .findAny();
                    if (elementalBondsBlockOptional.isPresent()) {
                        matchElementalBondsBlockList.add(elementalBondsBlockOptional.get());
                    } else {
                        // 匹配失败
                        matchSuccess = false;
                        break;
                    }
                }
                if (matchSuccess) {
                    // 匹配成功，返回
                    return new ElementalBondsShapeMatchResult(elementalBondsShapeConfig, matchElementalBondsBlockList);
                }
                if (elementalBondsShapeConfig.getNeedCount() == elementalBondsBlockList.size()) {
                    // 匹配失败 && 格子数和所需格子数相同 => 该形状全部失败
                    break;
                }
            }
        }
        return null;
    }

    /**
     * 顺时针旋转90度
     */
    private static int[][] rotate90(int[][] tmpArrArr) {
        int newHei = tmpArrArr[0].length;
        int newWid = tmpArrArr.length;

        int[][] newArrArr = new int[newHei][newWid];
        for (int y = 0; y < newHei; y++) {
            for (int x = 0; x < newWid; x++) {
                // 新x = 旧y
                // 新y = 旧宽度 - 旧x - 1， 旧宽度 = 新高度
                try {
                    newArrArr[y][x] = tmpArrArr[x][newHei - y - 1];
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return newArrArr;
    }

    /**
     * 水平翻转
     */
    private static int[][] flipHorizontally(int[][] tmpArrArr) {
        int newHei = tmpArrArr.length;
        int newWid = tmpArrArr[0].length;

        int[][] newArrArr = new int[newHei][newWid];
        for (int y = 0; y < newHei; y++) {
            for (int x = 0; x < newWid; x++) {
                // 新x = 旧宽度 - 旧x - 1， 旧宽度 = 新宽度
                // 新y = 旧y
                newArrArr[y][x] = tmpArrArr[y][newWid - x - 1];
            }
        }
        return newArrArr;
    }

    /**
     * 生成匹配点
     */
    private static List<List<Integer>> buildMatchPoint(int[][] arrArr) {
        // 找最左下的点
        int baseX = -1;
        int baseY = -1;
        for (int y = 0; y < arrArr.length; y++) {
            for (int x = 0; x < arrArr[y].length; x++) {
                if (arrArr[y][x] == 1) {
                    baseX = x;
                    baseY = y;
                    break;
                }
            }
            if (baseX != -1) {
                break;
            }
        }

        if (baseX == -1) {
            return null;
        }

        // 其他点转化为相对点
        List<List<Integer>> listList = new ArrayList<>();
        for (int y = 0; y < arrArr.length; y++) {
            for (int x = 0; x < arrArr[y].length; x++) {
                if (arrArr[y][x] == 1) {
                    if (x == baseX && y == baseY) {
                        continue;
                    } else {
                        List<Integer> list = new ArrayList<>();
                        list.add(x - baseX);
                        list.add(y - baseY);
                        listList.add(list);
                    }
                }
            }
        }

        // 排序
        listList.sort((o1, o2) -> {
            int compare = o1.get(1).compareTo(o2.get(1));
            if (compare != 0) {
                return compare;
            }
            return o1.get(0).compareTo(o2.get(1));
        });

        return listList;
    }

    /**
     * 获取唯一key用于去重
     */
    private static String getPointListKey(List<List<Integer>> listList) {
        StringBuilder sb = new StringBuilder();
        for (List<Integer> list : listList) {
            sb.append(list.get(0));
            sb.append(",");
            sb.append(list.get(1));
            sb.append(";");
        }
        return sb.toString();
    }

}
